
	/************************************************************************************************
	  
		Factory: Class
			
		Methods:	
			c		Class						(cid, data)								- sid: 3.0
			md	getMetaData			(id)											- sid: 3.0

			b		isAbstract			()												- sid: 3.0
			b		isClassOf				(obj)											- sid: 3.0
			b		isSubClassOf		(c)												- sid: 3.0
			b		isSuperClassOf	(c)												- sid: 3.0
					
		Legend:		
			data:
			inherits 				   -> jsl.Class 		| []<jsl.Class>
			exposes					   -> jsl.Interface | []<jsl.Interface>
			initializer
			
			'name' |'in_name'	 -> instance 	method/var
			'st_name'          -> static 		method/var
			'ab_name'          -> abstract	method
		
		MetaData:
			super, interfaces, classes, static, var, methods, abstract

		Note:
			The super classes/interfaces var/method/static,abstract... conflicts are resolved with a 
			priority level assigned from left(high) to right(low) 
			
	************************************************************************************************/
	
	//-------------------------------------------------------------------------------
	jsl.Class = function(cid, data) {
		try {
			var a, b, c, md, obj, builder, bname, id, value, f, prefix, cids, walker, cx, len, params, toS, vOf, name
			
			//@d[-------------------------------------------------------------------------------
			if(arguments.length !== 2)	throw jsl.ParamError()			
			jsl.validate(cid	, "qid"	, "cid")
			jsl.validate(data	, "o"		, "data")						
			if(jsl.Class.__data[cid])		throw jsl.ParamError("AlreadyDefined:cid")//@d]
			
			//-------------------------------------------------------------------------------				
			cx = jsl.__go

			if(cid.indexOf(".") !== -1) {
				
				cids	= cid.split(".")													
				len		= cids.length - 1
				
				for(a = 0; a < len; cx = cx[cids[a]], a++) 				
					//@d[
					if(!jsl.isObject(cx[cids[a]]))	throw jsl.ParamError("BadValue:cid")//@d]			
					;							
			}
					
			//-------------------------------------------------------------------------------
			md								= {}
			md["abstract"]		= []		
			md["classes"] 		= []
			md["interfaces"]	= []
			md["methods"]			= []
			md["static"]			= []		
			md["super"]				= null
			md["var"]					= []
			this.__md					= md

			//-------------------------------------------------------------------------------
			bname		= cid.match(/[^\.]+$/)[0]
			builder = data[bname] || data["in_" + bname]
			cids		= {}
			
			//@d[												
			if(data[bname] && data["in_" + bname])	throw jsl.ParamError("Duplicated:data." + bname)
			if(builder && !jsl.isFunction(builder))	throw jsl.ParamError("BadType:data." + bname + ":function")
						
			for(id in data)
				if(data.hasOwnProperty(id) && id !== "inherits" && id !== "exposes" && id !== "initializer" && id !== bname) {

					prefix = id.slice(0, 3)

					if(prefix !== "st_") {
						
						if(prefix === "in_" || prefix === "ab_")
							id = id.slice(3)
							
						if(cids.hasOwnProperty(id))	throw jsl.ParamError("Duplicated:data." + id)
						cids[id] = true
					}
				}//@d]
			
			//Static block				
			//@d[-------------------------------------------------------------------------------			
			if(data.initializer != null && !jsl.isFunction(data.initializer))	throw jsl.ParamError("BadType:data.initializer:Function")//@d]
			
			//MetaData: interfaces				
			//-------------------------------------------------------------------------------			
			if(data.hasOwnProperty("exposes")) {

				obj		= jsl.isArrayLike(data.exposes) ? data.exposes : [ data.exposes ]
				len 	= obj.length
				cids 	= {}
				//@d[
				if(!len)	throw jsl.ParamError("EmptyArray:data.exposes")//@d]

				for(a = 0; a < len; a++) { 
					//@d[
					name = obj[a].getName()
					
					jsl.validate(obj[a], "interface", "data.exposes[" + a + "]")				
					if(cids.hasOwnProperty(name))	throw jsl.ParamError("AlreadyDefined:data.exposes[" + a + "]" + name)//@d]				
					
					md.interfaces = md.interfaces.concat(obj[a], obj[a].getMetaData("interfaces"))//@d[					
					cids[name] 		= true//@d]
				}
				
				//no sort, the order of the interfaces is an information								
				md.interfaces = jsl.__mlang.array_unique.call(md.interfaces)
			}
			
			//MetaData: classes, super
			//-------------------------------------------------------------------------------			
			if(data.hasOwnProperty("inherits")) {

				obj 				= jsl.isArrayLike(data.inherits) ? data.inherits : [ data.inherits ]
				len					= obj.length
				md["super"] = obj[0]
				cids 				= {}

				//@d[
				if(!len)	throw jsl.ParamError("EmptyArray:data.inherits")//@d]

				for(a = 0; a < len; a++) {
					//@d[
					name = obj[a].getName()
					
					jsl.validate(obj[a], "class", "data.inherits[" + a + "]")				
					if(cids.hasOwnProperty(name))	throw jsl.ParamError("AlreadyDefined:data.inherits[" + a + "]" + name)//@d]				
					
					md.classes 	= md.classes.concat(obj[a], obj[a].getMetaData("classes"))//@d[
					cids[name] 	= true//@d]
				}
								
				//no sort, the order of the classes is an information								
				md.classes = jsl.__mlang.array_unique.call(md.classes)
			}
													
			//MetaData: static
			//-------------------------------------------------------------------------------			
			obj = []

			for(id in data) if(data.hasOwnProperty(id) && id.slice(0, 3) === "st_")	
				obj.push({ id: id.slice(3), value: data[id], inherited: false })

			len	= md.classes.length
			for(a = 0; a < len; a++) obj = obj.concat(md.classes[a].getMetaData("static"))

			len	= md.interfaces.length
			for(a = 0; a < len;	a++) obj = obj.concat(md.interfaces[a].getMetaData("var"))
			
			md["static"] = jsl.__mlang.array_unique.call(obj, { rule: function(e1, e2) { return e1.id !== e2.id } })
			md["static"].sort(function(s1, s2) { return s1.id < s2.id ? -1 : 1 })
			
			//MetaData: abstract
			//-------------------------------------------------------------------------------
			obj = []

			for(id in data) if(data.hasOwnProperty(id) && id.slice(0, 3) === "ab_")	
				obj.push({ id: id.slice(3), value: data[id], inherited: false })

			len	= md.classes.length
			for(a = 0; a < len; a++) obj = obj.concat(md.classes[a].getMetaData("abstract"))

			md["abstract"] 	= jsl.__mlang.array_unique.call(obj, { rule: function(e1, e2) { return e1.id !== e2.id } })												
			md["abstract"].sort(function(s1, s2) { return s1.id < s2.id ? -1 : 1 })
						
			//MetData: var, methods
			//-------------------------------------------------------------------------------			
			obj = []

			for(id in data) {

				prefix = id.slice(0, 3)

				if(data.hasOwnProperty(id) && id !== "inherits" && id !== "exposes" && id !== "initializer" && id !== bname) {
					if(prefix !== "ab_" && prefix !== "st_")
						obj.push({ id: prefix === "in_" ? id.slice(3) : id, value: data[id], inherited: false })	
					
					if(id === "toString")			toS = true
					else if(id === "valueOf")	vOf = true					
				}
			}
			
			//@sys: Explorer 8 - not enumerates toString/valueOf methods also if they are not js natives
			if(!toS && data.hasOwnProperty("toString"))	obj.push({ id: "toString"	, value: data["toString"]	, inherited: false })	
			if(!vOf && data.hasOwnProperty("valueOf"))	obj.push({ id: "valueOf"	, value: data["valueOf"]	, inherited: false })	
						
			len = md.classes.length			
			for(a = 0; a < len; a++) 
				obj = obj.concat(md.classes[a].getMetaData("var"), md.classes[a].getMetaData("methods"))
																	
			obj	= jsl.__mlang.array_unique.call(obj, { rule: function(e1, e2) { return e1.id !== e2.id } })
			len	= obj.length
						
			for(a = 0; a < len;	a++) {	
				
				id 		= obj[a].id
				value	= obj[a].value	
				
				if(jsl.isFunction(value)) {
				
					md["methods"].push(obj[a])	
					
					for(c = md["abstract"].length - 1; c >= 0; c--)
						if(md["abstract"][c].id === id) 
							break
							
					if(c >= 0) 
						md["abstract"].splice(c, 1)
				}
				else {
					//@d[
					if(jsl.Object.test(md["abstract"], function(n, v) { return n < this.length && v.id === id }))	
						throw jsl.ParamError("BadType:data." + id + ":function")//@d]
						
					md["var"].push(obj[a])
				}
			}
			
			md["var"].sort		(function(s1, s2) { return s1.id < s2.id ? -1 : 1 })
			md["methods"].sort(function(s1, s2) { return s1.id < s2.id ? -1 : 1 })
			
			//Interfaces methods implemetation check
			//@d[-------------------------------------------------------------------------------
			for(a = md["interfaces"].length - 1; a >= 0; a--) {
				
				obj = md["interfaces"][a].getMetaData("methods")
				
				for(b = obj.length - 1; b >= 0; b--) {
				
					for(c = md["methods"].length - 1; c >= 0; c--)
						if(md["methods"][c].id === obj[b].id) {
							
							params = jsl.__mlang.function_getParameters.call(md["methods"][c].value).join("")
							 
							if(params !== jsl.__mlang.function_getParameters.call(obj[b].value).join(""))	throw jsl.ParamError("BadSignature:data." + obj[b].id)
							break
						}
					
					if(c === -1)	throw jsl.ParamError("NotImplemented:data." + obj[b].id)
				}
			}//@d]

			//Constructor build
			//-------------------------------------------------------------------------------						
      if(md["abstract"].length) 
        c  = function() { throw jsl.MisuseError("AbstractClass:" + name) }
      else 
				c = function() {
					try {
						
						//if we call the constructor on a prototype, the __proto points to that prototype creating
						//an in finite loop					
						if(this instanceof arguments.callee && !this.hasOwnProperty("__proto")) {
							this.constructor	= arguments.callee
							this.__cname			= cid
							this.__sid				= cid
							this.__proto 			= arguments.callee.prototype
						}
	
						if(builder)	return builder.apply(this, arguments)
					}
					catch(e) {
						//@sys: FireFox 3.6.13 - arguments.callee is readonly, can not be setted to another function
						jsl.throwError(e, this, arguments)
					}
				}
			
			//MetaData update
			//-------------------------------------------------------------------------------      
			walker = function(id, v) { if(id < this.length) if(v.from) v.inherited = true; else v.from = c }
			
			jsl.Object.walk(md["static"]	, walker)
			jsl.Object.walk(md["abstract"], walker)
			jsl.Object.walk(md["var"]			, walker)
			jsl.Object.walk(md["methods"]	, walker)
			
			//Static class properties
			//-------------------------------------------------------------------------------      
      obj = md["static"]  
			for(a = obj.length - 1; a >= 0; a--) c[obj[a].id] = obj[a].value

			//Instance properties
			//-------------------------------------------------------------------------------
			obj = md.classes
			
			if(obj.length) {
				
				//abtsract constructor bypass
				jsl.__vars.f.prototype = obj[0].prototype
				c.prototype = new jsl.__vars.f
				
				for(a = obj.length - 1; a >= 0; a--) 
					for(b in obj[a].prototype)
						c.prototype[b] = obj[a].prototype[b]
			}							
			else 
				c.prototype = new jsl.Object
			
      c.prototype.__name 			= cid
      c.prototype[bname] 			= c
			c.prototype.__class			= c
			c.prototype.constructor	= obj.length ? obj[0] 					: jsl.Object
			c.prototype.__proto			= obj.length ? obj[0].prototype : jsl.Object.prototype

			for(obj = md["var"], len = obj.length, a = 0; a < len; a++) 
				if(!obj[a].inherited)
					c.prototype[obj[a].id] = obj[a].value
						
			for(obj = md["methods"], len = obj.length, a = 0; a < len; a++) 
				if(!obj[a].inherited) {
					
					if(true || jsl.__debug)	
						f = function() {
							try {
								var args
								return arguments.callee.__f.apply(this, arguments)						
							}
							catch(e) {
								//@sys: 	FireFox 3.6.13 - arguments.callee is readonly, can not be setted to another function
								//@info:	a new args array because the callee must point to the true function not at the wrapper
								//				In this mode the stacktrace is populated with the arguments names not p0,p1...
								args 				= Array.prototype.slice.call(arguments)
								args.callee	= arguments.callee.__f 
								jsl.throwError(e, this, args)
							}
						}
						else {
							params 	= jsl.__mlang.function_getParameters.call(obj[a].value)
							params 	= params.concat("try{" + jsl.__mlang.function_getBody.call(obj[a].value) + "}catch(e){jsl.throwError(e,this,arguments)}")
							f 			= Function.apply(null, params)						
						}					

					f.__f										= obj[a].value
					f.__name								= obj[a].id
					f.__f.__name						= obj[a].id //@info: stacktrace purpose only -> the function name instead of 'anonymous'
					obj[a].value						= f
					c.prototype[obj[a].id]	= f
				}
      
			//Private class data
			//-------------------------------------------------------------------------------
			//@sys: name for functions objects in Chrome 4.1.249.1045 is a read only property			
			c.__name 			= cid
			c.__md				= md
			c.__signature	= jsl.__signatures["jsl.Class"]
		
			//Public class methods
			//-------------------------------------------------------------------------------
			c.getName					= jsl.Object.prototype.getName
			c.isAbstract			= jsl.Class.isAbstract
			c.getMetaData			= jsl.Class.getMetaData
			c.isClassOf				= jsl.Class.isClassOf
			c.isSubClassOf		= jsl.Class.isSubClassOf
			c.isSuperClassOf	= jsl.Class.isSuperClassOf
			
			if(data.initializer)
				data.initializer.call(c.prototype)
			
			return jsl.Class.__data[cid] = cx[cid.slice(cid.lastIndexOf(".") + 1)] = c
		}
		catch(e) {
      jsl.throwError(e, jsl, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Class.prototype = jsl.Object()
	//-------------------------------------------------------------------------------
	jsl.Class.__name 		= "jsl.Class"
	jsl.Class.__data 		= []
//	jsl.Class.__native =
  //-------------------------------------------------------------------------------
  jsl.Class.getMetaData = function(id) {
    try {
    	var md, a
    	//@d[
      if(arguments.length !== 1)  throw jsl.ParamError()
			jsl.validate(id, "s+", "id")
			if(!this.__md.hasOwnProperty(id))	throw jsl.ParamError("BadValue:id")//@d]				
			
			if(id === "super")	
				md = this.__md["super"]
			else 		
				if(id != "interfaces" && id != "classes") md = jsl.Object.clone(this.__md[id], 1)
				else 																			md = jsl.Object.clone(this.__md[id])
    	
			return md
    }
    catch(e) {
      jsl.throwError(e, this, arguments)
    }
  }
	//-------------------------------------------------------------------------------
	jsl.Class.isAbstract = function() {
		try {//@d[
			if(arguments.length)	throw jsl.ParamError()//@d]
			return !!this.__md["abstract"].length
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Class.isClassOf = function(obj) {
		try {
			var v
			//@d[
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(obj, "o", "obj")//@d]
						
			v = obj.getClass && obj.getClass()
			
			if(v) 
				v = v === this || jsl.__mlang.array_contains.call(v.getMetaData("classes"), this)
			
			return v
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Class.isSubClassOf = function(c) {
		try {//@d[
			if(arguments.length	!== 1)	throw jsl.ParamError()
			jsl.validate(c, "class", "c")//@d]
			
			return jsl.__mlang.array_contains.call(this.__md["classes"], c)			
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Class.isSuperClassOf = function(c) {
		try {//@d[
			if(arguments.length	!== 1)	throw jsl.ParamError()
			jsl.validate(c, "class", "c")//@d]
			
			return jsl.__mlang.array_contains.call(c.__md["classes"], this)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
